﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace System.Threading.Workers
{
  /// <summary>
  /// Performs work on a background thread
  /// </summary>
  public abstract class TimedWorker : Worker
  {
    #region Fields
    private TimeSpan _interval;

    public TimeSpan Interval
    {
      get { return _interval; }
      set
      {
        if (IsStarted)
          throw new InvalidOperationException("Cannot change the interval while the worker is started");
        _interval = value;
      }
    }
    private DateTime _lastExecution;

    public DateTime LastExecution
    {
      get { return _lastExecution; }
    }
    private bool _executeOnStart;

    public bool ExecuteOnStart
    {
      get { return _executeOnStart; }
    }
    #endregion

    #region Properties

    #endregion

    #region Constructors
    public TimedWorker(string name, TimeSpan interval)
      : this(name, interval, true)
    {

    }

    public TimedWorker(string name, TimeSpan interval, bool executeOnStart)
      : base(name)
    {
      #region Validation
      if (interval.TotalMilliseconds <= 0)
        throw new ArgumentOutOfRangeException("interval", "interval must be breater than zero");
      #endregion
      _interval = interval;
      _executeOnStart = executeOnStart;
    }

    #endregion

    #region Methods
    public void InitiateWork()
    {
      WaitHandle.Set();
    }
    #endregion

    #region Abstract Declarations
    //protected abstract void CancelWork();
    //protected abstract void PerformWork();
    #endregion

    #region Overrides
    protected override bool CanPerformWork
    {
      get
      {
        if (_lastExecution + _interval > DateTime.Now)
          return false;
        else
        {
          _lastExecution = DateTime.Now;
          return true;
        }
      }
    }

    protected override void OnStarted(EventArgs e)
    {
      _lastExecution = DateTime.Now;

      if (_executeOnStart)
      {
        WaitHandle.Set();
        _lastExecution = DateTime.MinValue;
      }

      base.OnStarted(e);
    }
    #endregion
  }
}
